﻿using System;
using System.Collections.Generic;
using Common.Logging;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using TSharp.Core.Exceptions;
using TSharp.Core.Osgi;

namespace TSharp.Core.Unity
{
    /// <summary>
    /// 服务定位情景上下文实现
    /// </summary>
    /// <remarks>
    /// 1、2011-09-28 需要进行重构以便优化代码 @tangjingbo
    /// </remarks>
    /// <author>
    /// tangjingbo
    /// </author>
    public partial class UnityServiceSituation : IServiceSituation, IDisposable
    {
        private readonly ILog log = LogManager.GetLogger("UnityServiceSituation");
        public bool ThrowExceptionNullSessionRequest;

        #region 常量

        /// <summary>
        /// 系统容器key
        /// </summary>
        private const string CACHEKEY_SYSTEM_CONTAINER = "CONTAINER_SYSTEM";

        /// <summary>
        /// 会话容器KEY
        /// </summary>
        private const string CACHEKEY_SESSION_CONTAINER = "CONTAINER_SESSION";

        /// <summary>
        /// 请求容器key
        /// </summary>
        private const string CACHEKEY_REQUSET_CONTAINER = "CONTAINER_REQUEST";

        /// <summary>
        /// 线程容器Key
        /// </summary>
        private const string CACHEKEY_THREAD_CONTAINER = "CONTAINER_THREAD";


        /// <summary>
        /// 系统级别容器名称
        /// </summary>
        public static string CONFIG_CONTAINER_NAME_SYSTEM = "system";

        /// <summary>
        /// 会话级别容器名称
        /// </summary>
        public static string CONFIG_CONTAINER_NAME_SESSION = "session";

        /// <summary>
        /// 请求级别容器名称
        /// </summary>
        public static string CONFIG_CONTAINER_NAME_REQUEST = "request";

        /// <summary>
        /// 请求级别容器名称
        /// </summary>
        public static string CONFIG_CONTAINER_NAME_THREAD = "thread";

        #endregion

        #region IDisposable Members

        public void Dispose()
        {

        }

        #endregion

        #region IServiceSituation Members

        public IServiceLocator GetRequest()
        {
            return GetOrCreateRequestWrapper();
        }

      

        public IServiceLocator GetSession()
        {
            return GetOrCreateSessionWrapper();
        }
     
        public IServiceLocator GetThread()
        {
            return GetOrCreateThreadWrapper();
        }
       
        public IServiceLocator GetRoot()
        {
            return GetOrCreateRootWrapper();
        }
      
        #endregion

        #region Helper

        private UnityConfigurationSection _unitySection;

        /// <summary>
        /// unity配置节点
        /// <para>by tangjingbo at 2009-11-4 14:38</para>
        /// </summary>
        /// <value></value>
        internal UnityConfigurationSection UnitySection
        {
            get
            {
                if (_unitySection != null)
                {
                    return _unitySection;
                }
                _unitySection = WebConfigUtil.GetSection<UnityConfigurationSection>("unity");
                return _unitySection;
            }
        }

        private void Configure(IEnumerable<RegServiceAttribute> services, IUnityContainer unityContainer)
        {
            foreach (RegServiceAttribute lb in services)
            {
                Register(lb, unityContainer);
            }
        }

        private void Register(RegServiceAttribute lb, IUnityContainer unityContainer)
        {
            LifetimeManager lifetime = GetLifetime(lb);
            if (lb.IsDefault || string.IsNullOrEmpty(lb.Name))
            {
                if (lb.IntfType != null)
                    unityContainer.RegisterType(lb.IntfType, lb.ImplType, lifetime);
                else if (lb.ImplType != null)
                    unityContainer.RegisterType(lb.ImplType, lifetime);
            }
            if (!string.IsNullOrEmpty(lb.Name))
            {
                if (lb.IntfType != null)
                    unityContainer.RegisterType(lb.IntfType, lb.ImplType, lb.Name, lifetime);
                else if (lb.ImplType != null)
                    unityContainer.RegisterType(lb.ImplType, lb.Name, lifetime);
            }
        }

        private LifetimeManager GetLifetime(RegServiceAttribute rs)
        {
            if (rs.IsCached)
                return new ContainerControlledLifetimeManager();
            return new PerResolveLifetimeManager();
        }

        #endregion

        private void Dispose(IDisposable dispose)
        {
            if (dispose != null)
                dispose.Dispose();
        }

        #region Nested type: ServiceLocatorException

        public class ServiceLocatorException : CoreException
        {
            private Level l;
            private Type t;

            public ServiceLocatorException(Type queryType, Level level, Exception innerException)
                : base(string.Format("服务定位错误！Level:{0} ,Type:{1}", level, queryType.FullName), innerException)
            {
                t = queryType;
                l = level;
            }
        }

        #endregion

        #region Nested type: UnityLocatorWrapper

        private class UnityLocatorWrapper : IServiceLocator
        {
            private readonly Level _level;
            internal IUnityContainer unity;

            public UnityLocatorWrapper(IUnityContainer unitycontainer, Level level)
            {
                unity = unitycontainer;
                _level = level;
            }

            #region IServiceLocator Members

            public TService Get<TService>()
            {
                try
                {
                    return unity.Resolve<TService>();
                }
                catch (Exception ex)
                {
                    var e = new ServiceLocatorException(typeof(TService), Level, ex);
                    throw e;
                }
            }

            public TService Get<TService>(string name)
            {
                return unity.Resolve<TService>(name);
            }

            public object Get(Type type)
            {
                try
                {
                    return unity.Resolve(type);
                }
                catch (Exception ex)
                {
                    ServiceLocatorException e = WarpException(type, ex);
                    throw e;
                }
            }

            public object BuildUp(Type type, object instance)
            {
                try
                {
                    return unity.BuildUp(type, instance);
                }
                catch (Exception ex)
                {
                    ServiceLocatorException e = WarpException(type, ex);
                    throw e;
                }
            }

            public void Dispose()
            {
                Dispose(unity);
                unity = null;
                GC.SuppressFinalize(this);
            }

            public IEnumerable<TService> GetAll<TService>()
            {
                return unity.ResolveAll<TService>();
            }

            public IEnumerable<object> GetAll(Type type)
            {
                return unity.ResolveAll(type);
            }

            public object Get(Type type, string name)
            {
                return unity.Resolve(type, name);
            }

            public Level Level
            {
                get { return _level; }
            }

            #endregion

            private ServiceLocatorException WarpException(Type t, Exception innerException)
            {
                return new ServiceLocatorException(t, Level, innerException);
            }

            private void Dispose(IDisposable dispose)
            {
                if (dispose != null)
                    dispose.Dispose();
            }
        }

        #endregion
    }
}